package com.zHan.system.service.impl;


import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.zHan.model.dto.AssginMenuDto;
import com.zHan.model.system.SysMenu;
import com.zHan.model.system.SysRoleMenu;
import com.zHan.model.vo.RouterVo;
import com.zHan.system.exception.MyException;
import com.zHan.system.mapper.SysMenuMapper;
import com.zHan.system.mapper.SysRoleMenuMapper;
import com.zHan.system.mapper.SysUserRoleMapper;
import com.zHan.system.service.ISysMenuService;
import com.zHan.system.utils.MenuHelper;
import com.zHan.system.utils.RouterHelper;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.ArrayList;
import java.util.List;

/**
 * <p>
 * 菜单表 服务实现类
 * </p>
 *
 * @author zHan
 * @since 2023-06-23
 */
@Service
@Transactional
public class SysMenuServiceImpl extends ServiceImpl<SysMenuMapper, SysMenu> implements ISysMenuService {

    @Autowired
    private SysMenuMapper menuMapper;

    @Autowired
    private SysRoleMenuMapper sysRoleMenuMapper;

    @Autowired
    private SysRoleMenuMapper roleMenuMapper;

    @Autowired
    private SysUserRoleMapper userRoleMapper;

    /**
     * 菜单列表（树形）
     *
     * @return
     */
    @Override
    public List<SysMenu> selectNodes() {
        // 查询所有菜单列表
        List<SysMenu> sysMenuList =
                menuMapper.selectList(Wrappers.<SysMenu>lambdaQuery().orderByAsc(SysMenu::getSortValue));

        // 生成对应格式的列表
        List<SysMenu> resultList = MenuHelper.buildTree(sysMenuList);

        return resultList;
    }

    /**
     * 递归删除
     *
     * @param id
     * @return
     */
    @Override
    public boolean removeMenuById(Long id) {
        // 查询当前删除菜单下面是否有子菜单，根据id是否对于parentId
        LambdaQueryWrapper<SysMenu> lambdaQueryWrapper = new LambdaQueryWrapper<>();
        lambdaQueryWrapper.eq(SysMenu::getParentId, id);
        // 查询是否存在
        Integer count = menuMapper.selectCount(lambdaQueryWrapper);
        if (count > 0) {
            throw new MyException(201, "请先删除子菜单");
        }
        //查询菜单信息，确定是否可以删除
        LambdaQueryWrapper<SysMenu> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper
                .eq(SysMenu::getStatus, 1)
                .eq(SysMenu::getId, id);
        //不能删除，抛出业务异常
        if (this.getOne(queryWrapper) != null) {
            throw new MyException(201, "菜单在启用状态，不能删除");
        }
        // 调用方法删除
        try {
            //先删除菜单表中的信息
            this.removeById(id);
            //再删除其他表中的数据
            roleMenuMapper.delete(Wrappers.<SysRoleMenu>lambdaQuery()
                    .eq(SysRoleMenu::getMenuId, id));
        } catch (Exception e) {
            throw new RuntimeException(e);
        }

        return true;
    }

    /**
     * 批量删除菜单
     *
     * @param ids
     * @return
     */
    @Override
    public boolean batchRemoveMenu(List<Long> ids) {
        for (Long id : ids) {
            // 查询当前删除菜单下面是否有子菜单，根据id是否对于parentId
            LambdaQueryWrapper<SysMenu> lambdaQueryWrapper = new LambdaQueryWrapper<>();
            lambdaQueryWrapper.eq(SysMenu::getParentId, id);
            // 查询是否存在
            Integer count = menuMapper.selectCount(lambdaQueryWrapper);
            if (count > 0) {
                throw new MyException(201, "请先删除子菜单");
            }
        }
        //查询菜单信息，确定是否可以删除
        LambdaQueryWrapper<SysMenu> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper
                .eq(SysMenu::getStatus, 1)
                .in(SysMenu::getId, ids);
        //不能删除，抛出业务异常
        if (this.count(queryWrapper) > 0) {
            throw new MyException(201, "有菜单在启用状态，不能删除");
        }
        // 调用方法删除
        try {
            //先删除菜单表中的信息
            this.removeByIds(ids);
            //再删除其他表中的数据
            roleMenuMapper.delete(Wrappers.<SysRoleMenu>lambdaQuery()
                    .in(SysRoleMenu::getMenuId, ids));
        } catch (Exception e) {
            throw new RuntimeException(e);
        }

        return true;
    }

    /**
     * 根据角色获取菜单
     *
     * @param roleId
     * @return
     */
    @Override
    public List<SysMenu> findSysMenuByRoleId(String roleId) {
        // 获取所有菜单，status=1
        LambdaQueryWrapper<SysMenu> sysMenuLambdaQueryWrapper = new LambdaQueryWrapper<>();
        sysMenuLambdaQueryWrapper.eq(SysMenu::getStatus, "1");
        List<SysMenu> sysMenuList = menuMapper.selectList(sysMenuLambdaQueryWrapper);

        // 根据角色id，获取角色分配的菜单列表
        LambdaQueryWrapper<SysRoleMenu> lambdaQueryWrapper = new LambdaQueryWrapper<>();
        lambdaQueryWrapper.eq(SysRoleMenu::getRoleId, roleId);
        List<SysRoleMenu> roleMenuList = sysRoleMenuMapper.selectList(lambdaQueryWrapper);

        // 从第二步中，得到所有菜单id
        List<String> menuList = new ArrayList<>();
        for (SysRoleMenu roleMenu : roleMenuList) {
            menuList.add(roleMenu.getMenuId());
        }

        // 数据处理，isSelect ，选中为true，未选中为false
        // 拿着分配菜单 和 所有菜单比对，有相同的，isSelect为true
        for (SysMenu sysMenu : sysMenuList) {
            if (menuList.contains(sysMenu.getId())) {
                sysMenu.setSelect(true);
            } else {
                sysMenu.setSelect(false);
            }
        }

        // 返回转换成树形结果，用MenuHelper的方法
        return MenuHelper.buildTree(sysMenuList);
    }

    /**
     * 给角色分配菜单
     *
     * @param assginMenuDto
     * @return
     */
    @Override
    public boolean assignMenuToRole(AssginMenuDto assginMenuDto) {
        // 根据角色id删除菜单列表
        LambdaQueryWrapper<SysRoleMenu> lambdaQueryWrapper = new LambdaQueryWrapper<>();
        lambdaQueryWrapper.eq(SysRoleMenu::getRoleId, assginMenuDto.getRoleId());
        sysRoleMenuMapper.delete(lambdaQueryWrapper);

        // 遍历菜单列表，将列表加到sysRoleMenu表
        List<String> menuIdList = assginMenuDto.getMenuIdList();
        for (String menuId : menuIdList) {
            SysRoleMenu sysRoleMenu = new SysRoleMenu();
            sysRoleMenu.setRoleId(assginMenuDto.getRoleId());
            sysRoleMenu.setMenuId(menuId);

            // 执行insert方法
            sysRoleMenuMapper.insert(sysRoleMenu);
        }

        return true;
    }

    /**
     * 根据userId查询菜单权限值
     *
     * @param userId
     * @return
     */
    @Override
    public List<RouterVo> getUserMenuList(String userId) {
        List<SysMenu> sysMenuList = null;
        // 判断是否为超级管理员（userId=1），可以操作全部的菜单
        if ("1".equals(userId)) {
            LambdaQueryWrapper<SysMenu> lambdaQueryWrapper = new LambdaQueryWrapper<>();
            lambdaQueryWrapper.eq(SysMenu::getStatus, "1");
            lambdaQueryWrapper.orderByAsc(SysMenu::getSortValue);
            sysMenuList = menuMapper.selectList(lambdaQueryWrapper);
        } else {
            // 不是超级管理员，要查询用户权限
            sysMenuList = menuMapper.selectMenuListByUserId(userId);
        }
        // 构建树形数据
        List<SysMenu> sysMenuTreeList = MenuHelper.buildTree(sysMenuList);
        // 构建路由
        return RouterHelper.buildRouters(sysMenuTreeList);
    }

    /**
     * 根据userId查询按钮权限值
     *
     * @param userId
     * @return
     */
    @Override
    public List<String> getUserButtonList(String userId) {
        List<SysMenu> sysMenuList = null;
        // 判断是否为超级管理员（userId=1），可以操作全部的菜单
        if ("1".equals(userId)) {
            LambdaQueryWrapper<SysMenu> lambdaQueryWrapper = new LambdaQueryWrapper<>();
            lambdaQueryWrapper.eq(SysMenu::getStatus, "1");
            lambdaQueryWrapper.orderByAsc(SysMenu::getSortValue);
            sysMenuList = menuMapper.selectList(lambdaQueryWrapper);
        } else {
            // 不是超级管理员，要查询用户权限
            sysMenuList = menuMapper.selectMenuListByUserId(userId);
        }
        // 在菜单数据中查找按钮的集合，取得数据的perms
        List<String> permsList = new ArrayList<>();
        // 遍历sysMenuList
        for (SysMenu sysMenu : sysMenuList) {
            // type等于2表示按钮
            if (sysMenu.getType() == 2) {
                permsList.add(sysMenu.getPerms());
            }
        }
        return permsList;
    }

    /**
     * 更改菜单状态
     *
     * @param id
     * @param status
     * @return
     */
    @Override
    public boolean updateStatus(Long id, Integer status) {
        SysMenu menu = menuMapper.selectById(id);
        menu.setStatus(status);
        return this.updateById(menu);
    }
}
